package core;

import gitobject.Blob;
import gitobject.Commit;
import gitobject.GitObject;
import gitobject.Tree;
import picocli.CommandLine.*;
import repository.Index;
import repository.Repository;
import utility.Utility;

import java.io.IOException;
import java.nio.file.Path;
import java.util.*;

@Command(
        name = "reset"
)

/**
 * 实现了jit reset命令，用于回退版本
 * 分为soft、mixed、hard三种模式
 */
public class JitReset implements Runnable{
    static class Exclusive {
        @Option(names = {"-s", "--soft"}, description = "Change HEAD Only") boolean soft;
        @Option(names = {"-m", "--mixed"}) boolean mixed;
        @Option(names = {"-h", "--hard"}) boolean hard;
    }
    @ArgGroup(exclusive = true, multiplicity = "0..1")
    Exclusive exclusive;

    @Option(names = {"--prefix"})
    Path prefix;

    @Parameters(description = "The Target Commit Key")
    String commit_key;

    Commit commit;

    @Override
    public void run() {
        try {
            // 处理HEAD
            if(commit_key.startsWith("HEAD")){
                if(commit_key.length() == 4){
                    commit_key = Utility.hex2string(
                            Repository.getInstance().getCurrentBranch().getCommit()
                    );
                } else {
                    if(commit_key.charAt(4) == '^'){
                        byte[] key = ((Commit) GitObject.findByKey(
                                Repository.getInstance().getCurrentBranch().getCommit())
                        ).getParent();
                        for(int i=5; i < commit_key.length() && key != null; i++){
                            if(commit_key.charAt(4) == '^'){
                                key = ((Commit) GitObject.findByKey(key)).getParent();
                            } else {
                                System.err.printf("fatal: Not a valid object name %s%n", commit_key);
                                System.exit(-1);
                            }
                        }
                        if(key == null){
                            System.err.printf("fatal: Not a valid object name %s(No Parent)%n", commit_key);
                            System.exit(-1);
                        }
                        commit_key = Utility.hex2string(key);
                    } else if(commit_key.charAt(4) == '~' && commit_key.length() > 5){
                        try {
                            int num = Integer.parseInt(commit_key.substring(5));
                            if(num < 0){
                                throw new NumberFormatException();
                            }
                            byte[] key = Repository.getInstance().getCurrentBranch().getCommit();
                            for(;num > 0 && key!=null;num--){
                                key = ((Commit) GitObject.findByKey(key)).getParent();
                            }
                            if(key == null){
                                System.err.printf("fatal: Not a valid object name %s(No Parent)%n", commit_key);
                                System.exit(-1);
                            }
                            commit_key = Utility.hex2string(key);
                        } catch (NumberFormatException e){
                            System.err.printf("fatal: Not a valid object name %s%n", commit_key);
                            System.exit(-1);
                        }
                    } else {
                        System.err.printf("fatal: Not a valid object name %s%n", commit_key);
                        System.exit(-1);
                    }
                }
            }
            System.out.println(commit_key);
            GitObject commit = GitObject.findByKey(commit_key);
            if(commit.getType() != GitObject.Type.Commit){
                throw new IllegalArgumentException("Not A Commit.");
            }
            this.commit = (Commit) commit;
            if(exclusive == null || exclusive.mixed){
                mixed();
            } else if(exclusive.hard){
                hard();
            } else if(exclusive.soft){
                soft();
            } else {
                System.err.println("Unknown Option.");
            }
        } catch (Exception e){
            throw new RuntimeException(e);
        }

    }
    /**
     * 实现jit reset --mixed
     * @throws IOException
     */
    public void mixed() throws IOException {
        Repository.getInstance().getCurrentBranch().setCommit(commit.getKey()); // 修改HEAD
        Index index = Repository.getInstance().getIndex();
        index.switchTo(commit_key); // 切换Index
        index.write();
    }
    /**
     * 实现jit reset --soft
     * @throws IOException
     */
    public void soft(){
        Repository.getInstance().getCurrentBranch().setCommit(commit.getKey()); // 修改HEAD
    }
    /**
     * 实现实现jit reset --hard
     * @throws IOException
     */
    public void hard() throws IOException {
        Repository.getInstance().getCurrentBranch().setCommit(commit.getKey()); // 修改HEAD
        Index index = Repository.getInstance().getIndex();
        List<Path> need_remove = index.switchTo(commit_key);// 切换Index，并获取需要删除的文件
        // 删除文件
        for(Path path: need_remove){
            path = Repository.getInstance().getWorkTree().resolve(path);
            if(!path.toFile().delete()){
                System.err.printf("Fatal: failed to delete %s", path);
            }
        }
        Tree tree = (Tree) GitObject.findByKey(commit.getTree());
        if(prefix == null){prefix = Repository.getInstance().getWorkTree();}
        tree.restoreContent(prefix);
        index.write();
    }
}
